import pandas as pd
import datetime
import random
from pyecharts import options as opts
from pyecharts.charts import HeatMap, Page, Line, Grid
from pyecharts.components import Table
from bs4 import BeautifulSoup



def create_heatmap(result_df, label, x_name, y_name):
    pivot_df = result_df.pivot_table(
        values=f'{label}',
        index=f'{y_name}',  # Y轴作为行
        columns=f'{x_name}',  # X轴作为列
        aggfunc='mean'  # 处理重复值：取平均值
    )
    rows = len(pivot_df)
    cols = len(pivot_df.columns)
    datas = []
    for i in range(rows):
        for j in range(cols):
            datas.append([j, i , pivot_df.iloc[i, j]])
    if label == "max_drawdown":
        range_color = ["#00FF00", "#FFFF00", "#FF0000"][::-1]  # 绿-黄-红
    else:
        range_color = ["#00FF00", "#FFFF00", "#FF0000"]  # 绿-黄-红
    # 绘制热力图
    heatmap = (
        HeatMap()
        .add_xaxis(pivot_df.columns.tolist())
        .add_yaxis(
            f"{label}",
            pivot_df.index.tolist(),
            datas,
            label_opts=opts.LabelOpts(is_show=False),
        )
        .set_global_opts(
            title_opts=opts.TitleOpts(title=f"{label}热力图"),
            visualmap_opts=opts.VisualMapOpts(
                min_=result_df[f"{label}"].min(),
                max_=result_df[f"{label}"].max(),
                is_calculable=True,
                range_color=range_color,
            ),
            tooltip_opts=opts.TooltipOpts(
                trigger="item",
                axis_pointer_type="cross"
            ),
        )
    )
    return heatmap


def create_data_table(df, title):
    """创建数据表格"""
    # 转换数据为表格格式
    headers = df.columns.tolist()
    rows = []
    for _, row in df.iterrows():
        rows.append([str(x) for x in row.tolist()])

    table = (
        Table()
        .add(headers, rows)
        .set_global_opts(
            title_opts=opts.ComponentTitleOpts(title=title, subtitle="")
        )
    )
    return table


def create_line_chart(df, title, x_label, y_labels, holding_areas, date_length):
    """创建折线图"""
    y_label1, y_label2, y_label3, y_label4, y_label5, y_label6 = tuple(y_labels)
    line = (
        Line(init_opts=opts.InitOpts(width="90%"))
        .add_xaxis(df[x_label].tolist())
        .add_yaxis(f"nav", df[y_label1].tolist(),
                  is_smooth=True,
                  label_opts=opts.LabelOpts(is_show=False))
        .add_yaxis(f"nav_after_fee", df[y_label2].tolist(),
                   is_smooth=True,
                   label_opts=opts.LabelOpts(is_show=False))
        .add_yaxis("hold_btc", df[y_label3].tolist(),
                  is_smooth=True,
                  label_opts=opts.LabelOpts(is_show=False))
        .add_yaxis("ma", df[y_label4].tolist(),
                   is_smooth=True,
                   label_opts=opts.LabelOpts(is_show=False))
        .add_yaxis("up", df[y_label5].tolist(),
                   is_smooth=True,
                   label_opts=opts.LabelOpts(is_show=False))
        .add_yaxis("down", df[y_label6].tolist(),
                   is_smooth=True,
                   label_opts=opts.LabelOpts(is_show=False))
        # .set_series_opts(
        #     markarea_opts=opts.MarkAreaOpts(data=holding_areas)
        # )
        .add_yaxis(
            series_name="holding",
            y_axis=[None] * date_length,  # 空数据，只用于显示背景
            markarea_opts=opts.MarkAreaOpts(data=holding_areas),
            itemstyle_opts=opts.ItemStyleOpts(opacity=0),  # 隐藏线条
            label_opts=opts.LabelOpts(is_show=False),
        )
        .set_global_opts(
            title_opts=opts.TitleOpts(title=title),
            datazoom_opts=opts.DataZoomOpts(
                type_="inside",  # 组件类型：'slider' 或 'inside'
            ),  # 添加数据缩放组件
            tooltip_opts=opts.TooltipOpts(trigger="axis"),
            yaxis_opts=opts.AxisOpts(
                axislabel_opts=opts.LabelOpts(formatter="{value}")
            )
        )
    )
    return line


def gen_html(frequency, begin_date, x_name, y_name, last_date="2025-08-31"):
    path = f"{frequency}/{begin_date}/result/backtest_performance.csv"
    result_df = pd.read_csv(path)
    page = Page(layout=Page.SimplePageLayout)
    for label in ["annualized_return", "annualized_volatility", "annualized_shape", "turnover", "margin",
                         "fitness", "excess_return", "relative_return", "max_drawdown", "information_ratio",
                         "calmar_ratio", "yearly_count", "winning_rate", "profit_loss_ratio", "kelly_fraction"]:
        heatmap = create_heatmap(result_df, label, x_name, y_name)
        page.add(heatmap)
    for table_name in ["annualized_shape", "margin", "calmar_ratio", "information_ratio", "kelly_fraction"]:
        table_df = result_df.sort_values(by=table_name, ascending=False)
        # 取最高的两个值
        table_df = table_df[:2]
        count = 0
        for _, row in table_df.iterrows():
            count +=1
            m = int(row[f'{x_name}'])
            n = row[f'{y_name}']
            trade_log_df = pd.read_csv(f'{frequency}/{begin_date}/trade_log/trade_log_{m}_{n}.csv')
            holding_areas = []
            if trade_log_df.iloc[0]['action'] == "SELL":
                begin_datetime = datetime.datetime.strptime(begin_date, "%Y%m%d").date()
                holding_areas.append(
                    [
                        {"xAxis": begin_datetime.strftime("%Y-%m-%d"), "itemStyle": {"color": "rgba(235, 241, 222, 0.4)"}},
                        {"xAxis": trade_log_df.iloc[0]["date"], "itemStyle": {"color": "rgba(235, 241, 222, 0.4)"}}
                    ]
                )
                trade_log_df = trade_log_df[1:]
            for i in range(0, len(trade_log_df), 2):
                start_date = trade_log_df.iloc[i]["date"]
                assert trade_log_df.iloc[i]['action'] == "BUY"
                if i + 1 >= len(trade_log_df):
                    end_date = last_date
                else:
                    end_date = trade_log_df.iloc[i + 1]["date"]
                holding_areas.append(
                    [
                        {"xAxis": start_date, "itemStyle": {"color": "rgba(235, 241, 222, 0.4)"}},
                        {"xAxis": end_date, "itemStyle": {"color": "rgba(235, 241, 222, 0.4)"}}
                    ]
                )
            path = f"{frequency}/{begin_date}/nav/nav_{m}_{n}.csv"
            nav_df = pd.read_csv(path)
            y_labels = [f"nav0", "nav2", "nav(hold_btc)", "ma", "up", "down"]
            line = create_line_chart(nav_df, f"{x_name}={m},{y_name}={n}净值曲线({table_name}_top{count})", "date",
                                     y_labels, holding_areas, len(nav_df))
            page.add(line)
            table = Table()
            table.add(["指标", "值"],[[idx, val] for idx, val in row.items()])
            page.add(table)
            path = f"{frequency}/backtest_performance_by_year.csv"
            performance_by_year = pd.read_csv(path)
            performance_by_year = performance_by_year[(performance_by_year["M"] == m) & (performance_by_year["N"] == n)]
            performance_by_year = performance_by_year[performance_by_year["year"] >= int(begin_date[:4])]
            columns = ["year", "M", "N", "excess_return", "max_drawdown", "margin"]
            tabel = create_data_table(performance_by_year[columns], "年度表现")
            page.add(tabel)

    # 生成并保存
    html_path = f"{frequency}/{begin_date}/{frequency}_{begin_date}.html"
    page.render(html_path)
    with open(html_path, 'r', encoding='utf-8') as f:
        html_content = f.read()

    # 使用BeautifulSoup解析
    soup = BeautifulSoup(html_content, 'html.parser')

    # 1. 为表格容器添加样式
    chart_containers = soup.find_all(class_='chart-container')
    for container in chart_containers:
        if container.has_attr('style'):
            container['style'] += 'overflow-x: auto;'
        else:
            container['style'] = 'overflow-x: auto;'
    # 保存修改后的HTML
    with open(html_path, 'w', encoding='utf-8') as file:
        file.write(str(soup))


if __name__ == '__main__':
    gen_html("1d", "20170101", "M", "N", "2025-08-31")
    # for frequency in ["1d", "3h", "1h"]:
    #     for begin_date in ["20170101", "20200101", "20230101"]:
    #         gen_html(frequency, begin_date, "M", "N", "2025-08-31")
